package com.syscom.server.saclet;

import static com.syscom.safe.wac.management.SystemStatusCode.*;
import org.apache.log4j.Logger;

import com.syscom.server.action.ActionFactory;
import com.syscom.safe.tcplink.SafeTcpLinkException;
import com.syscom.safe.tcplink.SafeTcpLinkManager;
import com.syscom.safe.tcplink.server.api.Saclet;
import com.syscom.safe.tcplink.server.api.SacletSession;
import com.syscom.safe.tcplink.vo.Message;
import com.syscom.safe.wac.buf.SacInputBuffer;
import com.syscom.safe.wac.management.SacManager;
import com.syscom.safe.wac.service.SystemService;
import com.syscom.safe.wac.txbean.TxContext;
import com.syscom.shared.server.action.Action;
import com.syscom.shared.vo.ResponseStatus;

public class QDCActionController extends Saclet {
	private static Logger mLogger = Logger.getLogger(QDCActionController.class.getName());
		
	private static SacManager mSystemManager = SacManager.getInstance();
	
	private void beforeAction(SacletSession session, SacInputBuffer req) throws SafeTcpLinkException {
		return;
    }
	
	private void afterAction(SacletSession session,  SacInputBuffer req,  byte[] resp) throws SafeTcpLinkException {
		return;
    }
	
	/**
	 * Server 收到 client request 後, 呼叫 aciton 前, 所做的檢核
	 * 
	 * @param session
	 * @param req
	 * @param action
	 * @return
	 */
	private boolean isLegalAccess(SacletSession session, SacInputBuffer req, String action, String funcCd) {
		return true;
	}
	
	protected byte[] handleSyncRequest(SacletSession session, Message msg) throws SafeTcpLinkException {
		StringBuilder logBuffer = new StringBuilder();
		
		long lSystemStatusCode = mSystemManager.getSystemStatus();
		
		// checking if system error or halted
    	if (lSystemStatusCode != STATUS_NORMAL) {	// return system error to client
    		logBuffer.setLength(0);
    		
    		logBuffer.append("System error(status-code=").append(mSystemManager.getStatusCode());
    		logBuffer.append("  reason-code=").append(mSystemManager.getSystemErrCode());
    		logBuffer.append("  msg=").append(mSystemManager.getSystemErrMsg()).append(").");
    		
    		throw new SafeTcpLinkException(logBuffer.toString(), mSystemManager.getSystemErrCode());  
    	}
    	
    	SystemService svc = mSystemManager.getAbnormalService();
    	if (svc != null) {  // return service error to client
    		logBuffer.setLength(0);
    		
    		logBuffer.append("Abnormal service: svc-name=").append(svc.getServiceName());
    		logBuffer.append("  err-msg=").append(svc.getErrMsg());
    		
			throw new SafeTcpLinkException(logBuffer.toString(), svc.getErrCode());    			
    	}

    	long lStartTime = System.currentTimeMillis();
    	
    	// get action id here
    	SacInputBuffer bi = new SacInputBuffer(msg.getMessage());
    	String strActId = null;
    	String strFuncCd = null;
		TxContext ctx = new TxContext(TxContext.TYPE_SESSION_TCPLINK, session);
		
		try {
			strActId = bi.readShortString();
			bi.mark();  // mark to skip action id
			
			strFuncCd = bi.readShortString();
			
			if (mLogger.isInfoEnabled()) {
				logBuffer.setLength(0);
				
				logBuffer.append(">>>>>>>>> Processing synchronous request: handler=QdActionController  sess=");
				logBuffer.append(session.getIoSession().getRemoteAddress());
				logBuffer.append("  action=").append(strActId);
				logBuffer.append("  funcCd=").append(strFuncCd);
				logBuffer.append("  req-len=").append(msg.getMessage().length);
				
				mLogger.info(logBuffer.toString());
			}
					
			if (isLegalAccess(session, bi, strActId, strFuncCd) != true) {
				throw new SafeTcpLinkException("Authentication/Authorization failed.", SafeTcpLinkManager.ERR_AUTHEN_USER_FAILED);
			}
			
			bi.reset();
			beforeAction(session, bi);
			bi.reset();
			
			byte[] resp = null;
			Action act = null;
			
			try {
				// load action here
				act = ActionFactory.getAction(strActId);
			} 
			catch (Exception ex) {
				logBuffer.setLength(0);
				
				logBuffer.append("Failed to load action while executing sync request:");
				logBuffer.append(" action=").append(strActId);
				logBuffer.append("  msg=").append(ex.toString());
				
				throw new SafeTcpLinkException(logBuffer.toString(), SafeTcpLinkManager.ERR_LOAD_ACTION_FAILED);
			}
			
			resp = act.executeSyncRequest(ctx, bi);

			// 後端 Business Exception 產生, roll back transaction
			if (new SacInputBuffer(resp).readByte() == ResponseStatus.OK) {
				ctx.commitAllJoinTx();
			}
			else {
				ctx.rollbackAllJoinTx();
			}
			
			bi.reset();
			afterAction(session, bi, resp);
			if (mLogger.isInfoEnabled()) {
				logBuffer.setLength(0);
				
				logBuffer.append("<<<<<<<<<< Process synchronous request done: handler=QdActionController");
				logBuffer.append("  sess=").append(session.getIoSession().getRemoteAddress());
				logBuffer.append("  action=").append(strActId);
				logBuffer.append("  funcCd=").append(strFuncCd);
				logBuffer.append("  time-consumed=").append(System.currentTimeMillis() - lStartTime);
				logBuffer.append("  resp-len=").append(resp.length);
				
				mLogger.info(logBuffer.toString());
			}
			return resp;
		} 
		catch (RuntimeException ex) {
			ctx.rollbackAllJoinTx();
			
			logBuffer.setLength(0);
			
			logBuffer.append("Execute sync request failed:");
			logBuffer.append("  action=").append(strActId);
			logBuffer.append("  funcCd=").append(strFuncCd);
			logBuffer.append("  msg=").append(ex.toString());

			mLogger.error(logBuffer.toString(), ex);
			
			throw new SafeTcpLinkException(logBuffer.toString(), SafeTcpLinkManager.ERR_EXECUTE_ACTION_FAILED);
		} 
		catch (Exception ex) {
			ctx.rollbackAllJoinTx();
			
			logBuffer.setLength(0);
			
			logBuffer.append("Execute sync request failed:");
			logBuffer.append("  action=").append(strActId);
			logBuffer.append("  msg=").append(ex.toString());
			
			mLogger.error(logBuffer.toString(), ex);
			
			throw new SafeTcpLinkException(logBuffer.toString(), SafeTcpLinkManager.ERR_EXECUTE_ACTION_FAILED);
		} 
		finally {
			ctx.cleanup();
			ctx = null;
			
			bi.close();
			bi = null;
		}    	 	
	}

	protected void handleAsyncRequest(SacletSession session ,Message msg) throws SafeTcpLinkException {
		StringBuilder logBuffer = new StringBuilder();
		
		long lStartTime = System.currentTimeMillis();
    	// get action id here
    	SacInputBuffer bi = new SacInputBuffer(msg.getMessage());
    	String strActId = null;
    	String strFuncCd = null;
		TxContext ctx = new TxContext(TxContext.TYPE_SESSION_TCPLINK, session);
		
		try {
			strActId = bi.readShortString();
			bi.mark();  // mark to skip action id
			
			if (mLogger.isInfoEnabled()) {
				logBuffer.setLength(0);
				
				logBuffer.append(">>>>>>>>> Processing asynchronous request: handler=QdActionController");
				logBuffer.append("  sess=").append(session.getIoSession().getRemoteAddress());
				logBuffer.append("  action=").append(strActId);
				logBuffer.append("  funcCd=").append(strFuncCd);
				logBuffer.append("  req-len=").append(msg.getMessage().length);
				
				mLogger.info(logBuffer.toString());
			}
					
			if (isLegalAccess(session, bi, strActId, strFuncCd) != true) {
				throw new SafeTcpLinkException("Authentication/Authorization failed.", SafeTcpLinkManager.ERR_AUTHEN_USER_FAILED);
			}
			
			bi.reset();
			beforeAction(session, bi);
			bi.reset();
			
			Action act = null;
			
			try {
				// load action here
				act = ActionFactory.getAction(strActId);
			} 
			catch (Exception ex) {
				logBuffer.setLength(0);
				
				logBuffer.append("Failed to load action while executing async request:");
				logBuffer.append("  action=").append(strActId);
				logBuffer.append("  funcCd=").append(strFuncCd);
				logBuffer.append("  msg=").append(ex.toString());
				
				throw new SafeTcpLinkException(logBuffer.toString(), SafeTcpLinkManager.ERR_LOAD_ACTION_FAILED);
			}
			
			act.executeAsyncRequest(ctx, bi);
			ctx.commitAllJoinTx();
			
			bi.reset();
			afterAction(session, bi, null);
			if (mLogger.isInfoEnabled()) {
				logBuffer.setLength(0);
				
				logBuffer.append("<<<<<<<<<< Process asynchronous request done: handler=QdActionController");
				logBuffer.append("  sess=").append(session.getIoSession().getRemoteAddress());
				logBuffer.append("  action=").append(strActId);
				logBuffer.append("  funcCd=").append(strFuncCd);
				logBuffer.append("  time-consumed=").append(System.currentTimeMillis() - lStartTime);
				
				mLogger.info(logBuffer.toString());
			}
		} 
		catch (RuntimeException ex) {
			ctx.rollbackAllJoinTx();
			
			logBuffer.setLength(0);
			
			logBuffer.append("Execute sync request failed:");
			logBuffer.append("  action=").append(strActId);
			logBuffer.append("  funcCd=").append(strFuncCd);
			logBuffer.append("  msg=").append(ex.toString());
			
			mLogger.error(logBuffer.toString(), ex);
			
			throw new SafeTcpLinkException(logBuffer.toString(), SafeTcpLinkManager.ERR_EXECUTE_ACTION_FAILED);
		} 
		catch (Exception ex) {
			ctx.rollbackAllJoinTx();
			
			logBuffer.setLength(0);
			
			logBuffer.append("Execute sync request failed:");
			logBuffer.append("  action=").append(strActId);
			logBuffer.append("  funcCd=").append(strFuncCd);
			logBuffer.append("  msg=").append(ex.getMessage());
			
			mLogger.error(logBuffer.toString(), ex);
			
			throw new SafeTcpLinkException(logBuffer.toString(), SafeTcpLinkManager.ERR_EXECUTE_ACTION_FAILED);
		} 
		finally {
			ctx.cleanup();
			ctx = null;
			
			bi.close();
			bi = null;
		}
	}
}
